package com.fire.job.util;

import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.fire.job.constants.GlobalConstants;
import com.opensymphony.module.propertyset.PropertySet;
import com.opensymphony.module.propertyset.PropertySetManager;
import com.opensymphony.module.propertyset.xml.XMLPropertySet;


public class PropertyFactory {
	private static enum Type {
		JDBC {
			private static final String GLOBAL_KEY = "JOB";

			@Override
			protected PropertySet initPropertySet(PropertySet ps) {
				log.info("Property Manager start using JDBC style.");
				log.debug("Property manager using " + type + ".");
				Map<String, String> map = new HashMap<String, String>();
				map.put("globalKey", GLOBAL_KEY);
				ps = PropertySetManager.getInstance("jdbc", map);
				ps.setString(GlobalConstants.PROPERTY_TYPE, "JDBC");
				return ps;
			}
		},
		XML {
			@Override
			protected PropertySet initPropertySet(PropertySet ps) {
				log.info("Property Manager start using XML style.");
				ps = PropertySetManager.getInstance("xml", null);
				InputStream is = null;
				try {
					String[] pathes = xmlPath.split(";");
					for (String path : pathes) {
						is = FileUtil.getStream(path.trim());
						if (is != null) {
							log.info("Property manager using " + type + ", path: " + path.trim());
							((XMLPropertySet) ps).load(is);
							break;
						}
					}
					if(is==null){
						log.error("Property set xml path is not exist!");
					}
				} catch (ParserConfigurationException e) {
					log.error(e.getMessage(), e);
				} catch (IOException e) {
					log.error(e.getMessage(), e);
				} catch (Exception e) {
					log.error(e.getMessage(), e);
				} finally {
					IOUtils.closeQuietly(is);
				}
				ps.setString(GlobalConstants.PROPERTY_TYPE, "XML");
				return ps;
			}
		};
		protected abstract PropertySet initPropertySet(PropertySet ps);
	}

	private static PropertyFactory propertyInstance;
	private PropertySet ps = null;
	private static String xmlPath = null;
	/** 属性存储方式，可以为jdbc或xml */
	private static Type type = null;
	private static Log log = LogFactory.getLog(PropertyFactory.class);
	

	/**
	 * 获取实例
	 * 
	 * @return
	 */
	public synchronized static PropertyFactory getInstance() {
		if (propertyInstance == null) {
			propertyInstance = new PropertyFactory();
		}
		return propertyInstance;
	}

	/** 单例模式，不暴露构造器。 */
	private PropertyFactory() {
	}

	private void init() {
		// 1.正确性校验
		System.out.println("Type.XML:"+Type.XML);
		System.out.println("type:"+type);
		System.out.println("xmlPath:"+xmlPath);
		if (type == null || ((type.equals(Type.XML) && xmlPath == null))) {
			try {
                throw new Exception("The properties of Property Manager is not set.");
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
		}
		// 2.初始化
		ps = type.initPropertySet(ps);
	}

	public void setProperties(Properties props) {
		type = Type.valueOf(props.getProperty("property.type"));
		xmlPath = props.getProperty("property.path");
		if (StringUtil.isBlank(xmlPath)) {
			xmlPath = null;
		}
		init();
	}

	/**
	 * 获取PropertySet。配置文件位置位于/config/aibi_sca/socket/config.xml，相对于类根路径或项目根路径，程序能自动查找。
	 * 
	 * @return PropertySet
	 */
	public PropertySet getPropertySet() {
		if (ps == null) {
			init();
		}
		return ps;
	}
	
	
	/**
	 * 从外部设置ps
	 * @param ps
	 */
	public void setPropertySet(String typeStr,String propertyPath) {
		type = Type.valueOf(typeStr);
		xmlPath = propertyPath;
		init();
	}
	/**
	 * 保存PropertySet，存储于config/config.xml，相对于项目路径。<br>
	 * 注：往往在产品中以jar方式发布，这时classpath路径无法写入数据。
	 * 
	 * @param ps
	 */
	public void save() {
		if (Type.JDBC.equals(type)) {
			// leave empty
		} else if (Type.XML.equals(type)) {
			try {
				String[] pathes = xmlPath.split(";");
				InputStream is = null;
				for (String path : pathes) {
					is = FileUtil.getStream(path.trim());
					if (is != null) {
						log.debug("Property manager using " + type + ", path: " + path.trim());
						if(path.startsWith(GlobalConstants.CLASSPATH_PREFIX)){
							//文件路径在classpath时,做特殊处理
							path = path.substring(GlobalConstants.CLASSPATH_PREFIX.length());
							//设置config.xml路径
							URL url =PropertyFactory.class.getResource("");
							String currentClassPath = PropertyFactory.class.getName().replace('.', '/').replace("/PropertyFactory", "");
							String filePath = url.getPath();
							filePath = filePath.substring(1, filePath.length()-1).replace(currentClassPath, "");
							path = filePath+path;
							path = path.replace("bin", "resource");
							log.debug("Property manager absolute path :"+path);
						}
						((XMLPropertySet) ps).save(new BufferedOutputStream(new FileOutputStream(path)));
						break;
					}
				}
				
			} catch (FileNotFoundException e) {
				log.error(e.getMessage(), e);
			} catch (ParserConfigurationException e) {
				log.error(e.getMessage(), e);
			} catch (IOException e) {
				log.error(e.getMessage(), e);
			}
		}
	}
}
